package io.cici.cc.mybatis.plus.core.mapper;

import io.cici.cc.mybatis.lite.annotations.Parameter;
import io.cici.cc.mybatis.lite.exceptions.TooManyResultsException;
import io.cici.cc.mybatis.lite.executor.resultset.ResultContextHandler;
import io.cici.cc.mybatis.plus.core.conditions.Wrapper;
import io.cici.cc.mybatis.plus.core.conditions.query.QueryWrapper;
import io.cici.cc.mybatis.plus.core.toolkit.Constants;
import io.cici.cc.mybatis.plus.core.toolkit.Wrappers;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


public interface BaseMapper<T> extends Mapper<T> {

    /**
     * 插入一条记录
     *
     * @param entity 实体对象
     */
    int insert(T entity);

    /**
     * 根据 ID 删除
     *
     * @param id 主键ID
     */
    int deleteById(Serializable id);

    /**
     * 根据实体(ID)删除
     *
     * @param entity 实体对象
     * @since 3.4.4
     */
    int deleteById(T entity);

    /**
     * 根据 columnMap 条件，删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    default int deleteByMap(Map<String, Object> columnMap) {
        QueryWrapper<T> qw = Wrappers.query();
        return this.delete(qw.allEq(columnMap));
    }

    /**
     * 根据 entity 条件，删除记录
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    int delete(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 删除（根据ID或实体 批量删除）
     *
     * @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
     */
    int deleteBatchIds(@Parameter(Constants.COLL) Collection<?> idList);

    /**
     * 根据 ID 修改
     *
     * @param entity 实体对象
     */
    int updateById(@Parameter(Constants.ENTITY) T entity);

    /**
     * 根据 whereEntity 条件，更新记录
     *
     * @param entity        实体对象 (set 条件值,可以为 null)
     * @param updateWrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    int update(@Parameter(Constants.ENTITY) T entity, @Parameter(Constants.WRAPPER) Wrapper<T> updateWrapper);

    /**
     * 根据 Wrapper 更新记录
     */
    default int update(@Parameter(Constants.WRAPPER) Wrapper<T> updateWrapper) {
        return update(null, updateWrapper);
    }

    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     */
    T selectById(Serializable id);

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    List<T> selectBatchIds(@Parameter(Constants.COLL) Collection<? extends Serializable> idList);

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList               idList 主键ID列表(不能为 null 以及 empty)
     * @param resultContextHandler resultHandler 结果处理器 {@link ResultContextHandler}
     * @since 3.5.4
     */
    void selectBatchIds(@Parameter(Constants.COLL) Collection<? extends Serializable> idList,
                        ResultContextHandler<T> resultContextHandler);

    /**
     * 查询（根据 columnMap 条件）
     *
     * @param columnMap 表字段 map 对象
     */
    default List<T> selectByMap(Map<String, Object> columnMap) {
        QueryWrapper<T> qw = Wrappers.query();
        return this.selectList(qw.allEq(columnMap));
    }

    /**
     * 查询（根据 columnMap 条件）
     *
     * @param columnMap            表字段 map 对象
     * @param resultContextHandler resultHandler 结果处理器 {@link ResultContextHandler}
     * @since 3.5.4
     */
    default void selectByMap(Map<String, Object> columnMap, ResultContextHandler<T> resultContextHandler) {
        this.selectList(Wrappers.<T>query().allEq(columnMap), resultContextHandler);
    }

    /**
     * 根据 entity 条件，查询一条记录
     * <p>
     * 查询一条记录，例如 qw.last("limit 1") 限制取一条记录, 注意：多条数据会报异常
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default T selectOne(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper) {
        return this.selectOne(queryWrapper, true);
    }

    /**
     * 根据 entity 条件，查询一条记录，现在会根据{@code throwEx}参数判断是否抛出异常，如果为false就直接返回一条数据
     * <p>
     * 查询一条记录，例如 qw.last("limit 1") 限制取一条记录, 注意：多条数据会报异常
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @param throwEx      boolean 参数，为true如果存在多个结果直接抛出异常
     */
    default T selectOne(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper, boolean throwEx) {
        List<T> list = new ArrayList<>();

        this.selectList(queryWrapper, resultContext -> {
            T resultObject = resultContext.getObject();
            list.add(resultObject);
            if (!throwEx || resultContext.getCount() > 1) {
                resultContext.stop();
            }
        });
        int size = list.size();
        if (size == 1) {
            return list.get(0);
        } else if (size > 1) {
            if (throwEx) {
                throw new TooManyResultsException(
                        "Expected one result (or null) to be returned by selectOne(), but found multiple records");
            }
            return list.get(0);
        }
        return null;
    }

    /**
     * 根据 Wrapper 条件，判断是否存在记录
     *
     * @param queryWrapper 实体对象封装操作类
     * @return 是否存在记录
     */
    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0;
    }

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    Long selectCount(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 entity 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    List<T> selectList(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 entity 条件，查询全部记录
     *
     * @param queryWrapper         实体对象封装操作类（可以为 null）
     * @param resultContextHandler 结果处理器 {@link ResultContextHandler}
     * @since 3.5.4
     */
    void selectList(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultContextHandler<T> resultContextHandler);

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类
     */
    List<Map<String, Object>> selectMaps(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper         实体对象封装操作类
     * @param resultContextHandler 结果处理器 {@link ResultContextHandler}
     * @since 3.5.4
     */
    void selectMaps(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper,
                    ResultContextHandler<Map<String, Object>> resultContextHandler);

    /**
     * 根据 Wrapper 条件，查询全部记录
     * <p>
     * 注意： 只返回第一个字段的值
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    <E> List<E> selectObjs(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件，查询全部记录
     * <p>
     * 注意： 只返回第一个字段的值
     * </p>
     *
     * @param queryWrapper         实体对象封装操作类（可以为 null）
     * @param resultContextHandler 结果处理器 {@link ResultContextHandler}
     * @since 3.5.4
     */
    <E> void selectObjs(@Parameter(Constants.WRAPPER) Wrapper<T> queryWrapper,
                        ResultContextHandler<E> resultContextHandler);

}
